package com.winmastergames.andcwups;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.format.DateFormat;
import android.text.format.Time;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import java.util.*;
import java.text.*;

public class AndCWUpS extends Activity implements Runnable {
	private static final int MENU_START_SERVER = 0;
	private static final int MENU_STOP_SERVER = 1;
	/** Public Variables. */
	ListView LogView;
	ArrayList<HashMap<String, String>> myList;
    HashMap<String, String> map;
    SimpleAdapter mSchedule;
    int currentPos = 1;
    int bindPort = 80;
    protected static final int LogIndentifier = 0x1337; 
    protected static final int AcceptIndentifier = 0x101; 
    Thread tempThread = null;
    private ProgressDialog pd;
    private String threadOutput;
    private ArrayList<String> messageQueue = new ArrayList<String>();
    private int messageQueuePosition = 0;
    public ServerSocket srvSock;
    public Thread thread;
    public Boolean serverRunning = false;
    public Boolean serverCreated = false;
    public BufferedReader input;
    public DataOutputStream output;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //Set Public Variables
        pd = ProgressDialog.show(this, "Working..", "Starting AndCWUpS...", true, false);
        LogView  = (ListView) findViewById(R.id.ListView01);
        myList = new ArrayList<HashMap<String, String>>();
        map = new HashMap<String, String>();
        //Fix ListView Scrolling
        LogView.setVerticalFadingEdgeEnabled(true);
        LogView.setFocusable(false);
        //Add Start Log.
        addLogEntry("Application Started!");
        pd.dismiss();
    }
    
    /* Creates the menu items */
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(0, MENU_START_SERVER, 0, "Start Server");
        menu.add(1, MENU_STOP_SERVER, 1, "Stop Server & Exit");
        return true;
    }
    
    /* Handles item selections */
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case MENU_START_SERVER:
        	startServer();
            return true;
        case MENU_STOP_SERVER:
        	stopServer();
        	return true;
        }
        return false;
    }
    
    public void stopServer()
    {
    	if(serverRunning==true){
    		try {
				srvSock.close();
				serverRunning = false;
				addLogEntry("Server Socket Closed!");
				System.exit(0);
			} catch (IOException e) {
				addLogEntry(e.getMessage());
			}
    	}
    }
    
    public void startServer()
    {
    	if(serverRunning==false){
    		addLogEntry("Trying to Start Server...");
    		try
    		{
    			//Create Thread
    			pd.setMessage("Starting Server...");
    			pd.show();
    			if(serverCreated == false)
    			{
    				thread = new Thread(this);
    				serverCreated = true;
            		thread.start();
    			}
            	serverRunning = true;
            	pd.dismiss();
    		}
    		catch (Exception e)
    		{
    			addLogEntry(e.getMessage());
    			pd.dismiss();
    		}
    	}
    }
    
    public void run() {
    	messageQueue.add("Thread Running...");
        handler.sendEmptyMessage(0);
        messageQueue.add("Thread Still Running...");
        handler.sendEmptyMessage(0);
        //========================================
        //Bind Socket Server to Port.
        //========================================
        try {
			srvSock = new ServerSocket(22532);
			messageQueue.add("Binded Server to Port: 22532");
			handler.sendEmptyMessage(0);
			messageQueue.add("Binded Server to IP: " + srvSock.getInetAddress());
			
			handler.sendEmptyMessage(0);
		} catch (IOException e) {
			messageQueue.add(e.getMessage());
			handler.sendEmptyMessage(0);
		}
        //========================================
		//Start Listening.
		//========================================
		while(serverRunning == true)
		{
			messageQueue.add("Ready, Waiting for request...");
			handler.sendEmptyMessage(0);
			try {
				//Wait until some connects.
				Socket connectionSocket = srvSock.accept();
				//Get Client IP Address.
				InetAddress client = connectionSocket.getInetAddress();
				//Print Client IP
				messageQueue.add(client.getHostName() + " connected to server.");
				handler.sendEmptyMessage(0);
				//Read http request from client into a buffer.
				input = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
				//Prepare a outputstream from us to the client,
				//this will be used sending back our response
				//(header + requestedfile) to the client.
				output = new DataOutputStream(connectionSocket.getOutputStream());
				//Send Message to Handle the request.
				handler.sendEmptyMessage(1);
			}
			catch (Exception e)
			{
				messageQueue.add(e.getMessage());
				handler.sendEmptyMessage(0);
			}
		}
    }
    
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
        	switch(msg.what){
        		case 0:
        			pd.show();
        			pd.setMessage("Starting Server...");
        			addLogEntry(messageQueue.get(messageQueuePosition));
        			messageQueuePosition += 1;
        			if(messageQueuePosition == messageQueue.size())
        			{
        				pd.dismiss();
        			}
        			break;
        		case 1:
        			addLogEntry("HTTP REQUEST RECEIVED!");
        			addLogEntry("Processing HTTP Request");
        			http_handler(input, output);
        			break;
        	}
        }
    };
    
    private void http_handler(BufferedReader input, DataOutputStream output) {
        int method = 0; //1 get, 2 head, 0 not supported
        String http = new String(); //a bunch of strings to hold
        String path = new String(); //the various things, what http v, what path,
        String file = new String(); //what file
        String user_agent = new String(); //what user_agent
        try {
          //This is the two types of request we can handle
          //GET /index.html HTTP/1.0
          //HEAD /index.html HTTP/1.0
          String tmp = input.readLine(); //read from the stream
          String tmp2 = new String(tmp);
          tmp.toUpperCase(); //convert it to uppercase
          if (tmp.startsWith("GET")) { //compare it is it GET
            method = 1;
          } //if we set it to method 1
          if (tmp.startsWith("HEAD")) { //same here is it HEAD
            method = 2;
          } //set method to 2

          if (method == 0) { // not supported
            try {
              output.writeBytes(construct_http_header(501, 0));
              output.close();
              return;
            }
            catch (Exception e3) { //if some error happened catch it
              addLogEntry("error:" + e3.getMessage());
            } //and display error
          }
          //}

          //tmp contains "GET /index.html HTTP/1.0 ......."
          //find first space
          //find next space
          //copy whats between minus slash, then you get "index.html"
          //it's a bit of dirty code, but bear with me...
          int start = 0;
          int end = 0;
          for (int a = 0; a < tmp2.length(); a++) {
            if (tmp2.charAt(a) == ' ' && start != 0) {
              end = a;
              break;
            }
            if (tmp2.charAt(a) == ' ' && start == 0) {
              start = a;
            }
          }
          path = tmp2.substring(start + 2, end); //fill in the path
        }
        catch (Exception e) {
        	addLogEntry("errorr" + e.getMessage());
        } //catch any exception

        //path do now have the filename to what to the file it wants to open
        addLogEntry("\nClient requested:" + new File(path).getAbsolutePath() + "\n");
        FileInputStream requestedfile = null;

        try {
          //NOTE that there are several security consideration when passing
          //the untrusted string "path" to FileInputStream.
          //You can access all files the current user has read access to!!!
          //current user is the user running the javaprogram.
          //you can do this by passing "../" in the url or specify absoulute path
          //or change drive (win)

          //try to open the file,
          requestedfile = new FileInputStream("/sdcard/cwups_htdocs/" + path);
        }
        catch (Exception e) {
          try {
            //if you could not open the file send a 404
            output.writeBytes(construct_http_header(404, 0));
            //close the stream
            output.close();
          }
          catch (Exception e2) {}
          ;
          addLogEntry("error" + e.getMessage());
        } //print error to gui

        //happy day scenario
        try {
          int type_is = 0;
          //find out what the filename ends with,
          //so you can construct a the right content type
          if (path.endsWith(".zip") || path.endsWith(".exe")
              || path.endsWith(".tar")) {
            type_is = 3;
          }
          if (path.endsWith(".jpg") || path.endsWith(".jpeg")) {
            type_is = 1;
          }
          if (path.endsWith(".gif")) {
            type_is = 2;
            //write out the header, 200 ->everything is ok we are all happy.
          }
          output.writeBytes(construct_http_header(200, 5));

          //if it was a HEAD request, we don't print any BODY
          if (method == 1) { //1 is GET 2 is head and skips the body
            while (true) {
              //read the file from filestream, and print out through the
              //client-outputstream on a byte per byte base.
              int b = requestedfile.read();
              if (b == -1) {
                break; //end of file
              }
              output.write(b);
            }
            
          }
    //clean up the files, close open handles
          output.close();
          requestedfile.close();
        }

        catch (Exception e) {}

      }

      //this method makes the HTTP header for the response
      //the headers job is to tell the browser the result of the request
      //among if it was successful or not.
      private String construct_http_header(int return_code, int file_type) {
        String s = "HTTP/1.0 ";
        //you probably have seen these if you have been surfing the web a while
        switch (return_code) {
          case 200:
            s = s + "200 OK";
            break;
          case 400:
            s = s + "400 Bad Request";
            break;
          case 403:
            s = s + "403 Forbidden";
            break;
          case 404:
            s = s + "404 Not Found";
            break;
          case 500:
            s = s + "500 Internal Server Error";
            break;
          case 501:
            s = s + "501 Not Implemented";
            break;
        }

        s = s + "\r\n"; //other header fields,
        s = s + "Connection: close\r\n"; //we can't handle persistent connections
        s = s + "Server: SimpleHTTPtutorial v0\r\n"; //server name

        //Construct the right Content-Type for the header.
        //This is so the browser knows what to do with the
        //file, you may know the browser dosen't look on the file
        //extension, it is the servers job to let the browser know
        //what kind of file is being transmitted. You may have experienced
        //if the server is miss configured it may result in
        //pictures displayed as text!
        switch (file_type) {
          //plenty of types for you to fill in
          case 0:
            break;
          case 1:
            s = s + "Content-Type: image/jpeg\r\n";
            break;
          case 2:
            s = s + "Content-Type: image/gif\r\n";
          case 3:
            s = s + "Content-Type: application/x-zip-compressed\r\n";
          default:
            s = s + "Content-Type: text/html\r\n";
            break;
        }

        ////so on and so on......
        s = s + "\r\n"; //this marks the end of the httpheader
        //and the start of the body
        //ok return our newly created header!
        return s;
      }
    
    public void send_message_to_window(String s)
    {
    	addLogEntry(s);
    }
    
    public void addLogEntry(String input)
    {
    	map = new HashMap<String, String>();
        map.put("id", String.valueOf(currentPos));
        map.put("time", getTime());
        map.put("data", input);
        myList.add(map);
        mSchedule = new SimpleAdapter(this, myList, R.layout.row,
                new String[] {"id", "time", "data"}, new int[] {R.id.FIRST_CELL, R.id.SECOND_CELL, R.id.THIRD_CELL});
        LogView.setAdapter(mSchedule);
        currentPos += 1;
        LogView.setSelection(LogView.getCount() - 1);
    }
    public String getTime()
    {
    	Date date=new Date();
    	SimpleDateFormat sdf=new SimpleDateFormat("hh:mm:ss a");
    	String strDate=sdf.format(date);
    	return strDate;
    }
}